pub mod attr_unparsed;
pub mod attr_markers;
pub mod attr_source_file;
pub mod attr_constant_value;
pub mod attr_code;
pub mod attr_exceptions;
pub mod attr_line_number_table;
pub mod attr_local_variable_table;
pub mod attr_local_variable_type_table;
pub mod attr_bootstrap_methods;
pub mod attr_enclosing_method;

use std::{rc::Rc, cell::RefCell};

use crate::classfile::attribute_info::{attr_code::CodeAttribute, attr_unparsed::UnparsedAttribute};

use self::{
    attr_constant_value::ConstantValueAttribute, 
    attr_markers::{DeprecatedAttribute, SyntheticAttribute}, 
    attr_exceptions::ExceptionsAttribute, 
    attr_line_number_table::LineNumberTableAttribute, 
    attr_local_variable_table::LocalVariableTableAttribute, 
    attr_local_variable_type_table::LocalVariableTypeTableAttribute,
    attr_source_file::SourceFileAttribute, attr_enclosing_method::EnclosingMethodAttribute,
};

pub use attr_bootstrap_methods::{BootstrapMethodsAttribute, BootstrapMethod};

use super::{ClassReader, constant_pool::ConstantPool};


// attribute_info {
// u2 attribute_name_index; // 名称索引，必须是类常量池的有效⽆符号16位索引。
// u4 attribute_length; // 属性长度
// u1 info[attribute_length]; 属性表，指向常量池CONSTANT_Utf8_info
// }

pub trait AttributeInfo {
    fn read_info(&mut self, reader: &mut ClassReader);
}

// 读取属性表
pub fn read_attributes(reader: &mut ClassReader, cp: Rc<RefCell<ConstantPool>>) -> Vec<Attribute> {
    let attributes_count = reader.read_u16();
    let mut attributes = Vec::with_capacity(attributes_count as usize);
    for _ in 0..attributes_count {
        attributes.push(read_attribute(reader, cp.clone()));
    }
    attributes
}

// 读取单个属性
pub fn read_attribute(reader: &mut ClassReader, cp: Rc<RefCell<ConstantPool>>) -> Attribute {
    let attr_name_index = reader.read_u16() as usize;
    let attr_name = cp.borrow().get_utf8(attr_name_index);
    let attr_len = reader.read_u32() as usize;
    let mut attr_info = new_attribute_info(attr_name, attr_len, cp);
    attr_info.read_info(reader);
    attr_info
}

pub fn new_attribute_info(attr_name: String, attr_len: usize, cp: Rc<RefCell<ConstantPool>>) -> Attribute {
    match &attr_name[..] {
        "Code"                   => Attribute::CodeAttribute(CodeAttribute::new(cp)),
        "ConstantValue"          => Attribute::ConstantValueAttribute(ConstantValueAttribute::new()),
        "Deprecated"             => Attribute::DeprecatedAttribute(DeprecatedAttribute::new()),
        "Exceptions"             => Attribute::ExceptionsAttribute(ExceptionsAttribute::new()),
        "LineNumberTable"        => Attribute::LineNumberTableAttribute(LineNumberTableAttribute::new()),
        "LocalVariableTable"     => Attribute::LocalVariableTableAttribute(LocalVariableTableAttribute::new()),
        "LocalVariableTypeTable" => Attribute::LocalVariableTypeTableAttribute(LocalVariableTypeTableAttribute::new()),
        "SourceFile"             => Attribute::SourceFileAttribute(SourceFileAttribute::new(cp)),
        "Synthetic"              => Attribute::SyntheticAttribute(SyntheticAttribute::new()),
        "BootstrapMethods"       => Attribute::BootstrapMethodsAttribute(BootstrapMethodsAttribute::new()),
        "EnclosingMethod"       => Attribute::EnclosingMethodAttribute(EnclosingMethodAttribute::new(cp)),
        _                        => Attribute::UnparsedAttribute(UnparsedAttribute::new(attr_name, attr_len))
    }
}

// trait转换struct通过dyn Any转换修改太多。试用enum实现
pub enum Attribute {
    CodeAttribute(CodeAttribute),
    ConstantValueAttribute(ConstantValueAttribute),
    DeprecatedAttribute(DeprecatedAttribute),
    ExceptionsAttribute(ExceptionsAttribute),
    LineNumberTableAttribute(LineNumberTableAttribute),
    LocalVariableTableAttribute(LocalVariableTableAttribute),
    LocalVariableTypeTableAttribute(LocalVariableTypeTableAttribute),
    SourceFileAttribute(SourceFileAttribute),
    SyntheticAttribute(SyntheticAttribute),
    BootstrapMethodsAttribute(BootstrapMethodsAttribute),
    EnclosingMethodAttribute(EnclosingMethodAttribute),
    UnparsedAttribute(UnparsedAttribute),
}

impl AttributeInfo for Attribute {
    fn read_info(&mut self, reader: &mut ClassReader) {
        match self {
            Self::CodeAttribute(attribute) => attribute.read_info(reader),
            Self::ConstantValueAttribute(attribute) => attribute.read_info(reader),
            Self::DeprecatedAttribute(attribute) => attribute.read_info(reader),
            Self::ExceptionsAttribute(attribute) => attribute.read_info(reader),
            Self::LineNumberTableAttribute(attribute) => attribute.read_info(reader),
            Self::LocalVariableTableAttribute(attribute) => attribute.read_info(reader),
            Self::LocalVariableTypeTableAttribute(attribute) => attribute.read_info(reader),
            Self::SourceFileAttribute(attribute) => attribute.read_info(reader),
            Self::SyntheticAttribute(attribute) => attribute.read_info(reader),
            Self::BootstrapMethodsAttribute(attribute) => attribute.read_info(reader),
            Self::EnclosingMethodAttribute(attribute) => attribute.read_info(reader),
            Self::UnparsedAttribute(attribute) => attribute.read_info(reader),
        }
    }


}